#include "qpcrModel.h"

using namespace QPCRModel;


double Model::yingCTJiao(double *yingLvbo, double yuzhi, int end, int leh){

    double xiaoYuzhi=0;
    double daYuzhi=0;
    double CtJ;
    for(int i = end; i < leh; i++){
        if(*(yingLvbo+i) >= yuzhi){

          xiaoYuzhi = *(yingLvbo+i) - *(yingLvbo+i-1);
          daYuzhi = yuzhi - *(yingLvbo+i-1);
          CtJ = i + daYuzhi / xiaoYuzhi;
          i = leh;
        }
    }
    return CtJ;
}

double Model::getCt(double threshold, QVector<double> param, YAxisType type){
    double func_type = param[0];
    double fitting_conf = param[1];
    if(fitting_conf < 0.8){
        return 0;
    }
    funcModel* func;
    if(func_type == 0){
        func = new funcSigmoid;
        func->a = param[2];
        func->b = param[3];
        func->x0 = param[4];
        func->y0 = param[5];
        func->d = 1;
    }else if(func_type == 1){
        func = new funcRichards;
        func->a = param[2];
        func->b = param[3];
        func->x0 = param[4];
        func->y0 = param[5];
        func->d = param[6];
    }else{
        return 0;
    }

    if(type == RN){
        ;
    }else if(type == DELTA_RN){
        threshold += func->y0;
    }else if(type == LOG_RN){
        threshold = pow(10, threshold);
    }else if(type == LOG_DELTA_RN){
        threshold = pow(10, threshold) + func->y0;
    }
    return func->g(threshold);


}


double Model::linearFitting(const QVector<QPointF>& points_list, double* k, double* b)
{
    float sum_x2 = 0.0;
    float sum_y = 0.0;
    float sum_x = 0.0;
    float sum_xy = 0.0;

    int num = points_list.size();

    int i;
    for (i = 0; i < num; ++i)
    {
        sum_x2 += points_list[i].x() * points_list[i].x();
        sum_y += points_list[i].y();
        sum_x += points_list[i].x();
        sum_xy += points_list[i].x() * points_list[i].y();
    }


    float tmp = num * sum_x2 - sum_x * sum_x;
    if (abs(tmp) > 0.000001f)
    {
        *k = (num * sum_xy - sum_x * sum_y) / tmp;
        *b = (sum_x2 * sum_y - sum_x * sum_xy) / tmp;
    }
    else
    {
        *k = 0;
        *b = 0;
        return -1;
    }

    // 返回偏差平均值
    double stderror = 0;
    for(int i = 0; i < num; i ++){
        stderror += pow(- ((points_list[i].x()*(*k) - points_list[i].y() + (*b)) / sqrt((*k)*(*k)+1)), 2);
    }
    return sqrt(stderror/num);

}


double Model::distancePL(QPointF pt, double k, double b){
    return - ((pt.x()*k - pt.y() + b) / sqrt(k*k+1));   // 正负表示在直线上还是直线下
}

double Model::calDistance(double x1, double x2, double y1, double y2){
    return sqrt( pow(x1-x2, 2) + pow(y1-y2, 2) );
}

// 滤波器
QVector<QPointF>  Model::filter(const QVector<QPointF> &list, int type){

    int size = list.size();
    QVector<QPointF> res;

    if (type == 0){
        if(list.size() < 3){
            return list;
        }
        double coef = 1.0/3.0;


        res.append(QPointF(list[0].x(), list[0].y()*0.8 + list[1].y()*0.2));

        double t_value;
        for(int c = 1; c < size-1; c ++){
            t_value = list[c-1].y() * coef
                    + list[c].y()   * coef
                    + list[c+1].y() * coef;
            res.append(QPointF(list[c].x(), t_value));
        }

        res.append(QPointF(list[size-1].x(), list[size-1].y()*1 + list[size-2].y()*0));

    }

    if(type == 1){
        if(list.size() < 5){
            return list;
        }
        double t_value;
        t_value = list[0].y() * (+0.886)
                + list[1].y() * (+0.257)
                + list[2].y() * (-0.086)
                + list[3].y() * (-0.143)
                + list[4].y() * (+0.086);
        res.append(QPointF(list[0].x(), t_value));

        t_value = list[0].y() * (+0.257)
                + list[1].y() * (+0.371)
                + list[2].y() * (+0.343)
                + list[3].y() * (+0.171)
                + list[4].y() * (-0.143);
        res.append(QPointF(list[1].x(), t_value));

        for(int c = 2; c < size-2; c ++){
            t_value = list[c-2].y() * (-0.086)
                    + list[c-1].y() * (+0.343)
                    + list[ c ].y() * (+0.486)
                    + list[c+1].y() * (+0.343)
                    + list[c+2].y() * (-0.086);
            res.append(QPointF(list[c].x(), t_value));
        }

        t_value = list[size-5].y() * (-0.143)
                + list[size-4].y() * (+0.171)
                + list[size-3].y() * (+0.343)
                + list[size-2].y() * (+0.371)
                + list[size-1].y() * (+0.257);
        res.append(QPointF(list[size-2].x(), t_value));

        t_value = list[size-5].y() * (+0.086)
                + list[size-4].y() * (-0.143)
                + list[size-3].y() * (-0.086)
                + list[size-2].y() * (+0.257)
                + list[size-1].y() * (+0.886);
        res.append(QPointF(list[size-1].x(), t_value));
    }

    return res;
}



double Model::correlationPointList(const QVector<QPointF> &pointList){
    double Exy = 0, Ex = 0, Ey = 0, Ex2 = 0, Ey2 = 0;
    for(int c = 0; c < pointList.size(); c ++){
        Exy += pointList[c].x() * pointList[c].y();
        Ex  += pointList[c].x();
        Ey  += pointList[c].y();
        Ex2 += pointList[c].x() * pointList[c].x();
        Ey2 += pointList[c].y() * pointList[c].y();
    }
    double coef = 1.0 / pointList.size();
    Exy *= coef;
    Ex  *= coef;
    Ey  *= coef;
    Ex2 *= coef;
    Ey2 *= coef;

    return  (Exy - Ex * Ey) / ( sqrt(Ex2 - Ex*Ex) * sqrt(Ey2 - Ey*Ey) );

}

